home *** CD-ROM | disk | FTP | other *** search
- program MenuEngine; {Yet Another Menu System by Ed Keefe, APRIL '89 }
- uses dos, crt; {Public Domain Program: may be shared freely.
- No rights reserved.}
-
- Const
- maxitems = 9 ; { maximum number of items per submenu less 1}
- maxsubs = 9 ; { maximum number of submenus less 1}
- normbackground = brown ; normforeground = yellow;
- highbackground = lightgray ; highforeground = black;
- {You may pick other colors if you like.}
-
- type
- st15 = string[15]; {a short string}
-
- itemtype = record { Basic record structure for the menu.}
- r,c : byte; { Where ...}
- s : st15; { What ...}
- t : byte; { type of menu: 0=exec;1,2,3..= #submenu }
- end;
-
- submtype= record
- num : byte; {How many items in this submenu...}
- mnuitem : array [0..maxitems] of itemtype; { = 10 items}
- end;
-
- mnutype = array[0..maxsubs] of submtype; { = 10 submenus }
-
- var
- i,j,t, hcode,row,col,mcnt,subnum,ndx : byte;
- mnuara : mnutype; {--an array of records made up of a byte}
- parm : st15; {and an array of records of bytes and strings }
- code : integer;
- inf : text;
- ch : char;
- again : boolean;
- scr : byte;
- mode : word;
-
- function stupr(s:st15):st15; {converts string to uppercase}
- var i : byte;
- begin
- for i := 1 to length(s) do s[i]:=upcase(s[i]);
- stupr := s;
- end;
-
- procedure cursoron;
- var
- regs:registers; {registers defined in dos unit}
- begin
- if mode in[0..3] then
- begin
- regs.ah := $01; { restore color cursor }
- regs.ch := $06;
- regs.cl := $07;
- intr($10,regs);
- end
- else
- if (mode = 7) then
- begin
- regs.ah := $01; { restore mono cursor }
- regs.ch := $c;
- regs.cl := $d;
- intr($10,regs);
- end;
- end;
-
- procedure cursoroff;
- var
- regs:registers;
- begin { set bit 5 of cursor control byte }
- regs.ah := $01; { which turns cursor off }
- regs.ch := $20;
- intr($10,regs);
- end;
-
- procedure errmsg(n:byte);
- begin
- case n of
- 0 : write('Please use 1 to 10 items per menu.');
- 1 : write('Parm 1 must be H or V');
- 2 : write('Parm 2 = row');
- 3 : write('Parm 3 = col');
- 4 : write(paramstr(1),' file not found.');
- 5 : write('USAGE: MGN menufile.ext');
- end;
- cursoron;
- halt(255);
- end;
-
- procedure hvmnu(m:byte;horv:char); {Set up the record for horiz. or vert. menu}
- var i, place : byte;
- begin
- mnuara[m].num := paramcount-4; {put the number of items in the num field
- of the record}
- place := 0;
- for i := 0 to paramcount-4 do {repeat for the number of items in the subm}
- with mnuara[m].mnuitem[i] do {use the submenu[m] and the ith element from
- the menuitem field of the record}
- begin
- if horv = 'H' then { setup for horiz.menu structure}
- begin
- r:=row;
- c:=col+place;
- s:=' '+paramstr(i+4)+' '; {pad with blanks right and left}
- place:= place+length(paramstr(i+4))+2;
- end
- else
- begin {setup for vert. menu structure}
- r:=row+place;
- c:=col;
- s:=' '+paramstr(i+4);
- while length(s)<15 do s:=s+' '; {pad on the right with blanks}
- place:= place+1;
- end;
- if pos('*',paramstr(i+4))<>0 then {compute submenu number: 1,2,3...}
- begin {t:=0 by default with fillchar() }
- subnum:=succ(subnum); {Keep track of the submenus...}
- t:=subnum;
- end;
- end;
- end;
-
- procedure show_item(m,ndx,high:byte); { turn lightbar on/off }
- begin
- gotoxy(mnuara[m].mnuitem[ndx].c,mnuara[m].mnuitem[ndx].r);
- if high = 0 then textattr := normforeground+normbackground*$10
- else textattr := highforeground+highbackground*$10;
- write(mnuara[m].mnuitem[ndx].s);
- end;
-
- procedure disp_menu(m,ndx:byte);
- begin
- textattr:=normforeground+normbackground*$10;
- with mnuara[m] do { Display list }
- For ndx:=0 to mnuara[m].num do { the number of items is contained
- in the first field of the record}
- with mnuara[m].mnuitem[ndx] do
- begin
- gotoxy(c,r);
- write(s);
- end; { the submenu is now displayed. }
- end;
-
- function domenu(m: byte):byte; { show the menu;get choice;return value}
- Var count : byte;
- st : st15;
- Begin { domenu }
- disp_menu(m,ndx);
- ndx:=0;
- Repeat
- show_item(m,ndx,1); { highlight the item }
- ch := readkey; if ch = ^@ then ch:=readkey; {Fetch a scancode}
- case ch of { make a choice }
- #13 : if ndx=mnuara[m].num then domenu:=255
- else domenu := ndx+(m*10);
- #27 : domenu := 255;
- #8,'K','H' : begin show_item(m,ndx,0); {turn off the item}
- if ndx > 0 then ndx := ndx-1 {wraparound?}
- else ndx:=mnuara[m].num; end;
- ' ','M','P': begin show_item(m,ndx,0);
- if ndx < mnuara[m].num then ndx:=ndx+1
- else ndx:=0; end;
- 'G','I' : begin show_item(m,ndx,0); ndx :=0; end;
- 'O','Q' : begin show_item(m,ndx,0);ndx :=
- mnuara[m].num; end;
- else { Check for second character of item }
- Begin
- show_item(m,ndx,0); {turn off item}
- count:=ndx; {save ndx to count}
- Repeat
- count:=succ(count); {start here and look}
- If count > mnuara[m].num {at all items in}
- then count:=0; {the submenu.}
- st := mnuara[m].mnuitem[count].s;
- Until (count = ndx) Or
- (upcase(ch) = upcase(st[2]));
- ndx:=count {new or original ndx}
- End;
- end; {case}
- Until (ch = #13) Or (ch = #27);
- end;
-
- Begin { Main Program }
- mode := lastmode; {get current video mode}
- directvideo:=true; {snappier response}
- clrscr;
- scr := textattr; {built-in text background and color}
- cursoroff;
- fillchar(mnuara, sizeof(mnuara),0); {zero-out the array}
- if paramcount < 1 then errmsg(5); {do some error trapping}
- assign(inf,paramstr(1));
- {$I-} reset(inf);{$I+} {Is the menufile found?}
- if IOResult<>0 then errmsg(4);
- mcnt:=0; subnum:=0;
- while( not eof(inf)) and ( mcnt < 10) do
- begin
- readln(inf,string(ptr(prefixseg,$80)^)); {jam line into PSP}
- parm := stupr(paramstr(1)); {use paramstr/count}
- if not (parm[1] in ['H','V']) then errmsg(1); {to parse.}
- val(paramstr(2),row,code);if code <> 0 then errmsg(2);
- val(paramstr(3),col,code);if code <> 0 then errmsg(3);
- if (paramcount < 4) and (paramcount>10) then errmsg(0);
- hvmnu (mcnt,parm[1] ); {load a submenu}
- mcnt :=succ(mcnt);
- end; { we, now, have the mnuara loaded}
- close(inf);
- {Show main menu}
- subnum:=0; again:=true;
- repeat
- if subnum=0 then
- begin textattr:=scr ; clrscr; end;
- hcode := domenu(subnum);
- t := mnuara[subnum].mnuitem[ndx].t;
- {SEE Footnote1 for the next line}
- if((t<>0) and (hcode<>255)) or ((subnum<>0) and (hcode=255))
- then subnum:=t
- else again:=false;
- until not again;
- normvideo;
- cursoron;
- gotoxy(1,21); { <--- this is just for use with M.BAT}
- halt(hcode); { You may delete it from your version }
- End.
-
- Footnote1: At this point we have hcode,subnum, t: we want to determine); if we should repeat or exit the loop on the basis of these 3
- variables. What *should* happen is the following.
- In the main menu, if I press ESC or Exit[Return], I should
- quit the loop. Otherwise, if I press Return on a starred item,
- I should get a submenu. On the other hand, if I press a non-
- starred item, I should leave the loop with the value of hcode
- as my errorlevel. (Leaving the loop with ESC or Exit generates
- and errorlevel of 255. )
-
- If I am in a submenu and I press ESC or Quit[Return], I should
- return to the main menu. On the other hand, if I press Return
- on a non-starred option, I should leave the loop with the val-
- ue of hcode as my DOS errorlevel. Usually, submenu options will
- not be starred. But, just in case, if I press Return on a star-
- red item, I should get a further submenu.
-
- So, with 3 variables, each of which have "either-or" type val-
- ues, I know that I have 2^3=8 possible cases to consider. Here
- they are...
-
- SUBNUM ACTION STOP OR AGAIN
- (current Desired RETURN Boolean
- level of t=0 -> exec h=255; value to
- menuing) t<>0 ->do a h<>255; control
- submenu looping.
- -------------------------------------------------
- =0 =0 =255 false
- =0 =0 <>255 false
- =0 <>0 =255 false
- =0 <>0 <>255 true
- <>0 =0 =255 true
- <>0 =0 <>255 false
- <>0 <>0 =255 true
- <>0 <>0 <>255 true
-
- Initially, AGAIN is TRUE. I want a short way to determine when
- it will go FALSE.
-
- SO, I write...
-
- If ((subnum=0) and (t<>0) and (hcode<>255)) OR
- ((subnum<>0) and (t<>0) and (hcode<>255)) OR
- ((subnum<>0) and (t<>0) and (hcode=255)) OR
- ((subnum<>0) and (t<>0) and (hcode=255)) OR
- Then AGAIN := TRUE
- Else AGAIN := FALSE;
-
- Now, it's time to dig out the old Boolean Logic Book and
- simplify this expression.
-
- Abbreviating: -X means X <> 0 or X <> 255
- * means the logical AND (&&)
- + means the logical OR (!!)
- (S* -T * -H) + ( -S * -T * -H) + (-S * T * H) + (-S * -T * H)
- factoring out common expressions...
- (-T * -H) * (S + -S) + (-S * H) * (T + -T)
- always 1 always 1
- Skipping a couple of steps in logic, yields the following code..
- if((t<>0) and (hcode<>255)) or ((subnum<>0) and (hcode=255))
- *)
-
- And that's all he wrote...t'aint elegant, and not very sophisticated
- but MenuEngine makes a great "batch file enhancer", I think. If you
- want to get more elaborate, you can call the same program more than
- once in the same batch file and have several menus on the screen at
- the same time.
-
- You could try rewriting the program so that the default colors could
- be modified with some additional command-line parameters (along with
- the menufile name) and then you could have menus with different
- colors on the screen.
-
- You could add "boxes" around your options...You could make the whole
- thing into a TSR (but be careful..novices will pop it up in the
- middle of 1-2-3 and mess things up royally. )
-
- You could add a couple of procedures to save and restore the screen
- and use that in place of "clrscr;".
-
- And the ideas just keep coming...MenuEngine will get you started.
- It's up to you to enhance it. Let me know if you make any improvements
- or correct any bugs.
- --Ed Keefe [CIS 73277,1064]